\section{Administraci'on de memoria}
\label{sec:paginacion}

Ademas de la segmentaci'on la arquitectura IA32 provee otro mecanismo de administraci'on de memoria: la paginaci'on. El mismo divide, de forma estatica y no solapada, la memoria en bloques de 4Kb a los que llama p'aginas. Adem'as se provee una forma de reasignar p'aginas de memoria, definiendo direcciones virtuales que resuelven en direcciones f'isicas. Esta traducci'on se realiza autom'aticamente por el procesador utilizando al Directorio de P'aginas (PD) y las Tablas de P'aginas (PT).

Nuestro sistema debe tener una forma de administrar memoria y otorg'arsela a procesos
seg'un sea necesario. Para ello implementamos una pieza de c'odigo que denominamos MMU(memory management unit). La misma no solo administra la memoria, sino que tambi'en es lo suficientemente inteligente para armar esquemas de paginaci'on adecuados para cubrir las necesidades deseadas.

\subsection{Paginas libres de kernel y de usuario}
Para llevar cuenta de la memoria otrogada (espec'ificamente p'aginas entregadas) tenemos dos contadores globales: uno para p'agina de usuario
y otro para p'aginas de kernel. Para operar con ellos definimos las siguientes funciones:

\texttt{pagina$\_$libre$\_$kernel}: Como su nombre lo indica, se encarga de otorgar una p'agina libre
en la memoria de kernel, algoritmicamente es tan sensilla como incrementar el contador de p'aginas kernel en
el tama'no de una p'agina, verificando que no se halla llegado al limite establecido de memoria.

\texttt{pagina$\_$libre$\_$usuario}: An'alogamente a la funcion anterior hace lo propio, solo que incrementando en el tama'no
de una pagina el contador de la memoria de usuario. 

Cabe destacar que los contadores comienzan en la p'agina anterior a las direcciones pedidas por el enunciado, pues el invariante que mantendremos es que siempre apuntan a la 'ultima p'agina ocupada, de 'esta manera las funciones anteriormente descriptas primero aumentan el contador y luego dan el resultado, evitando una variable intermedia innecesaria. Adem'as definimos l'imites para las paginas entregadas. La 'ultima p'agina de kernel a entregar es la anterior a cuando comienzan las de usuario (direccion f'isica 2Mb), mientras que para las p'aginas de usuario definimos un l'imite de 2Mb total (por ende termina en la direcci'on f'isica 4Mb).

\subsection{Mapas de memoria}

Se nos pide inicializar el esquema de paginaci'on para el kernel con identity mapping a las direcciones 0x00000000 a 0x001FFFFF. Para ello definimos la funci'on \texttt{identity\_map} que toma como par'ametro la cantidad de memoria que debe mapearse. En nuestra implementaci'on la misma no puede superar los 4Mb. Dicha funci'on pide una p'agina libre del kernel para el PD, recorrre todas sus 1024 posiciones limpiandolas con entradas de p'aginas ausentes (bit menos significativo en cero). Luego pide otra p'agina para el PT y asigna dicha direccion (alineada a 4kb, con los ultimos dos bits encendidos, para el permiso R/W y Presente) a la primera entrada de la PD. Luego recorre dicho PT llenando las entradas con valores consecutivos (de a 4Kb), iniciando desde cero hasta la posicion indicada por el par'ametro (bytes/4), siempre encendiendo los bits de R/W y Presente. Por 'ultimo se llenan las entradas restantes con p'aginas no presentes y se devuelve la direcci'on de memoria donde se encuentra el PD.

Gracias a esta 'ultima funci'on la definici'on de \texttt{inicializar\_dir\_kernel} se reduce a invocarla con par'ametro igual a 4096 y asignar en el registro CR3 el resultado de dicha funci'on. Una vez armada la estructura de p'aginas solo resta activar paginaci'on desde el kernel. Para realizar esto debemos encender el bit m'as significativo del registro CR0. Entonces, utilizando la misma t'ecnica que cuando pasamos a modo protegido, bajamos el CR0 a un registro de prop'osito general, encendemos el bit, y lo volvemos a asignar al registro de control. Si todo es correctamente ejecutado deber'iamos poder correr la proxima instrucci'on con 'exito (y por suerte fue lo que sucedi'o!).

Una vez activada la paginaci'on debemos cambiar el mapa de memoria que utiliza el kernel. Por el momento, el mismo puede acceder a toda la memoria que estabams utilizando en 'este momento. Recordemos que el c'odigo del mismo esta cargado en las posiciones inferiores de memoria, luego estan las p'aginas libres de kernel hasta la direccion f'isica 2Mb y por 'ultimo las p'aginas libres de usuario hasta la posici'on 4Mb.

El nuevo mapa debe tener definido identity mapping solamente para los primeros 2Mb de memoria. Gracias a la funci'on previamente definida, es muy simple definir \texttt{inicializar\_dir\_usuario} como invocar a \texttt{identity\_map} con el par'ametro igual a 2048. Es importante aclarar que esta funci'on no setea el CR3 como su analoga del kernel, sino que devuelve el valor del mapa de memoria. Esto se debe a que esta funci'on se reutilizar'a en el futuro para armar los mapas de las tareas.

Entonces, para intercambiar el mapa de memoria del kernel definimos la funci'on \texttt{inicializar\_mmu} que invoca \texttt{inicializar\_dir\_usuario} y setea el resultado en el CR3. La misma la invocamos desdel el kernel. 

Una vez activada paginaci'on, utilizamos la rutina \texttt{IMPRIMIR$\_$TEXTO} que nos provee la c'atedra para imprimir el nombre del grupo en la esquina superior izquierda de la pantalla. 

\paragraph*{Observacion}
Al cargar la paginaci'on por primera vez quisimos revisar la primera posici'on de la PD. Sorprendidos nos encontramos con el valor 0x101023. Al inicio no pod'iamos justificar porque hay un 2 en el segundo nibble (deber'ia ser 0x101003), pero nos dimos cuenta que es el bit de \textit{accessed} es encendido por el procesador ya que accedimos a esa p'agina apenas activamos la paginaci'on. Lo comprobamos revisando el valor antes de activar la paginaci'on y lo encotramos como era debido.

\paragraph*{Pregunta 5:} Un espacio de direcciones virtuales de 4MB se
encuentra mapeado utilizando una pagina de ese mismo tama'no. Sin embargo se
desea tomar 4Kb dentro de ese espacio de direcciones y mapearlo en un espacio
fisico distinto  ?`es 'esto posible? 
?` C'omo? Realize pseudoc'odigo de ser necesario. \\
\textbf{Respuesta:} Si, es posible. La entrada de la PD que mapea esos 4Mb tiene el bit PSE encendido y por lo tanto los ultimos 22 bits de la direccion virtual se interpretan como el offset dentro de esa p'agina. Para redireccionar un subespacio de esa p'agina debemos cambiar esa entrada en el PD por una que tenga el bit PSE apagado. De esa manera, los 10 bits intermedios hacen referencia a la PT y los 'ultimos al ofset dentro de cada p'agina. Lo 'unico que resta hacer es crear todas esas PT, asignar sus direcciones de memoria en las entradas de la PD y establecer cada PT entry de manera que respete el mapeo anterior escepto en la porci'on de memoria que se quiere modificar. Esto no es dificl hacer pues antes la asignaci'on era de 4Mb consecutivos, por lo que tenemos que emular el mismo comportamiento con p'aginas de 4Kb.

%Si, para esto debemos  activar el bit Page Size en la entrada del directorio de p'aginas de 4MB y activar el PSE en el CR4 para accederlas. 



\paragraph*{Pregunta 6:}  Suponiendo que una tarea pueda modificar el
directorio de p'aginas. ?`Puede esta tarea acceder a cualquier posici'on de la
memoria? \\
\textbf{Respuesta:} Si, Podria modificar una de las entradas de directorio para referenciar al mismo
directorio de pa'ginas. Una vez accedido , puede alterar las entradas existentes
o crear nuevas, asi podr'ia acceder a cualquier posici'on. 

\paragraph*{Pregunta 7:} ?`Puede una tarea escribir todas las direcciones de
memoria de los 4Gb que le es posible direccionar? ?`Qu'e Dificultades genera?\\
\textbf{Respuesta:} En el caso que una tarea pueda escribir las direcciones de los 4Gb lo que podr'ia
pasar es que sobre escriba el kernel,la GDT, los directorios de p'aginas y
tablas de p'aginas, de esta manera lanzar'ian las diferentes excepciones del
procesador.

\subsection{Mapeando y desmapeando memoria}

Para mapear una p'agina particular dentro de un mapa de memoria, definimos una funci'on (\texttt{mapear\_pagina}) que toma una direcci'on virtual, el mapa (CR3) y la direcci'on f'isica. La misma busca el 'indice correspondiente a la direcci'on virtual dentro del PD (utilizando los 10 bits mas significativos de la virtual). De esta manera obtenemos la tabla de p'aginas y nos fijamos si esta presente. Si no lo est'a, obtenemos una p'agina libre de kernel para la PT, colocamos esta entrada en la PD y limpiamos la tabla con p'aginas no presentes. Si estaba presente entonces accedemos al PT ya definido. Luego (sea si estaba presente o no), seleccionamos con los bits 11 a 21 de la direcci'on virtual la posici'on de la tabla correspondiente a esa direcci'on virtual y asignamos la direcci'on fisica, alineada a 4Kb con los bits 0 y 1 encendidos (R/W y Presente). 


Para borrar un mapeo de una p'agina particular(\texttt{unmapear\_pagina}) hab'iamos realizado en una sola
funci'on en un primer momento. Luego con el avance del trabajo pr'actico se separ'o en dos funciones para mayor conveniencia. 


Primero hicimos una funci'on que nos devuelve la posici'on a borrar dentro de la PT. La misma realiza la b'usqueda empezando por el PD (dato apuntado por el CR3 pasado como par'ametro) de la misma manera que mapear. Si la encuentra devuelve la posici'on caso contrario devuelve cero. Por lo tanto \texttt{unmapear\_pagina} pide la posici'on a borrar y si la misma no es cero, accede a la direcci'on pasada y limpia el contenido, dejando la p'agina como ausente.

Es importante se'nalar que despues de eliminar un mapeo siempre se llama a la funcion TLBFLUSH. La misma limpia la TLB (Translation Lookside Buffer) siendo esta una memoria cache administrada por el procesador que almacena la relaci'on entre direcciones virtuales y fisicas para referenciarlas m'as r'apidamente, sin pasar por el proceso de traducci'on. De 'esta manera nos aseguramos de no acceder a posiciones de memoria obsoletas.

\subsection{Preguntas}

\paragraph*{Pregunta 8:} ?`Qu'e permisos pueden tener las tablas y directorios de p'aginas? ?`Cu'ales son los permisos efectivos de una direcci'on de memoria seg'un los permisos del directorio y tablas de p'aginas? \\
\textbf{Respuesta:} Cada directorio o tabla de p'aginas puede tener permiso de supervisor o usuario, el mismo se indica con el bit 2 tanto en el
la entrada de directorio de p'aginas como en la de tabla de p'aginas.

\paragraph*{Pregunta 9:} ?`Es posible desde dos directorios de p'agina referenciar a una misma tabla de p'aginas? \\
\textbf{Respuesta:} Si, es posible y sirve para crear memoria compartida entre los distintos procesos.

\paragraph*{Pregunta 10:} ?`Qu'e es el TLB (Translation Lookaside Buffer) y para qu'e sirve? \\
\textbf{Respuesta:} La TLB o Translation Lookaside Buffer es una cache que guarda las traducciones de direcci'on virtual a f'isica. Sirve para evitar hacer la traducci'on en cada acceso a memoria. Es importante notar que s'olo es necesario limpiarla cuando se hace un desmapeo, pues cuando se agrega una nueva entrada en el mapa 'este seguro no se encuentra en la cache. Sin embargo, si modifico una entrada sin eliminarla entonces s'i deberia limpiarla.



